package ch.fhnw.apsi.password;

import static java.util.Collections.unmodifiableList;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import ch.fhnw.apsi.beans.Credentials;

import com.sun.istack.internal.NotNull;

/**
 * Generates a random password. The password is stored into an array so that it can be {@link #scramble(char[])
 * scrambled}. (Note: This system receives the login-password as a String, so there the passwords exist as Strings.) *
 * 
 */
public final class PasswortGenerator {

  public static final int LENGTH = 12;
  /** @see Credentials#validatePassword() */
  private static final List<Character> alpha;
  /** @see Credentials#validatePassword() */
  private static final List<Character> number;
  /** @see Credentials#validatePassword() */
  private static final List<Character> special;
  static {
    final List<Character> _alpha = new ArrayList<>(26 * 2);
    for (char c = 'a'; c <= 'z'; c++)
      _alpha.add(c);
    for (char c = 'A'; c <= 'Z'; c++)
      _alpha.add(c);
    alpha = unmodifiableList(_alpha);
    final List<Character> _number = new ArrayList<>(64);
    for (char c = '0'; c <= '9'; c++)
      _number.add(c);
    number = unmodifiableList(_number);
    special = unmodifiableList(Arrays.asList('ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü', '.', '-', '_'));
  }

  /**
   * Overwrite all characters in an array of characters with a new password. That can also be used to scramble the
   * actual password. Crackers who get a memory-dump wont know which are actual passwords.
   */
  public static void randomPasswort(@NotNull final char[] array) {
    assert array.length == LENGTH;
    final SecureRandom rnd = new SecureRandom();
    // This makes sure that the password has per 4 characters about:
    // - 2 letters,
    // - one number,
    // - and one special character.
    for (int i = 0; i < LENGTH; i++)
      switch (rnd.nextInt(4)) {
      case 0:
        array[i] = number.get(rnd.nextInt(number.size()));
        break;
      case 1:
        array[i] = special.get(rnd.nextInt(special.size()));
        break;
      default:
        array[i] = alpha.get(rnd.nextInt(alpha.size()));
        break;
      }
    // assert Credentials.validatePassword(String.valueOf(array));
  }
}
